<?php

namespace App\Services\WxMass;

use App\Facades\EasyWechat;
use App\Models\WxMass;
use App\Services\SysConfig\SysConfigService;
use App\Services\WxCommon\WxError;
use App\Services\WxMass\WxMassInterface;

/**
 * 微信群发服务类
 * @package App\Services
 */
class WxMassService extends \App\Services\WxCommon\WxBase
{
    const MSG_TYPE_TEXT = 'text';//文本
    const MSG_TYPE_NEWS = 'news';//图文
    const MSG_TYPE_IMAGE = 'image';//图片
    const MSG_TYPE_VOICE = 'voice';//语音
    const MSG_TYPE_VIDEO = 'video';//视频
    const MSG_TYPE_CARD = 'card';//卡券

    //消息类型列表
    private $msgTypeList;
    //群发对象类别
    private $typeObjectList;

    /**
     * 构造函数
     */
    public function __construct($appid = '')
    {
        parent::__construct($appid);

        $this->typeObjectList = [
            self::MSG_TYPE_TEXT => __NAMESPACE__ . '\Factory\WxMassText',
            self::MSG_TYPE_NEWS => __NAMESPACE__ . '\Factory\WxMassNews',
            self::MSG_TYPE_IMAGE => __NAMESPACE__ . '\Factory\WxMassImage',
            self::MSG_TYPE_VOICE => __NAMESPACE__ . '\Factory\WxMassVoice',
            self::MSG_TYPE_VIDEO => __NAMESPACE__ . '\Factory\WxMassVideo',
            self::MSG_TYPE_CARD => __NAMESPACE__ . '\Factory\WxMassCard',
        ];
        //消息类别列表
        $this->msgTypeList = [
            self::MSG_TYPE_TEXT => '文本',
            self::MSG_TYPE_NEWS => '图文',
            self::MSG_TYPE_IMAGE => '图片',
            self::MSG_TYPE_VOICE => '语音',
            self::MSG_TYPE_VIDEO => '视频',
            self::MSG_TYPE_CARD => '卡券',
        ];
    }

    /**
     * 消息类别
     * @return array
     */
    public function getMsgTypeList()
    {
        return $this->msgTypeList;
    }

    /**
     * 获取回复消息类型
     * @param $msgType
     * @return mixed|string
     */
    public function getMsgTypeStr($msgType)
    {
        return isset($this->msgTypeList[$msgType]) ? $this->msgTypeList[$msgType] : '';
    }

    /**
     * 保存群发数据
     * @param $request
     * @return bool
     */
    public function save($request)
    {
        $massId = $request->mass_id ?? 0;
        if ($massId) {
            $massModel = WxMass::where('appid', $this->appid)->findOrFail($massId);
            if (!empty($massModel->msg_id)) {
                throw new \Exception('该群发已经推送不允许修改');
            }
        } else {
            $massModel = new WxMass;
        }
        $massModel->appid = $this->appid;
        $massModel->title = $request->title ?? '';
        $massModel->description = $request->description ?? '';
        $massModel->msg_type = $request->msg_type;
        //根据群发筛选方式格式化为不同的规则格式
        $filterType = $request->filter_rule['type'] ?? '';
        $massModel->filter_rule = (new FilterFactory())->createFilterObj($filterType)->formatInput($request);
        $massModel->is_open = (int)$request->is_open ?? [];
        $massModel->push_time = $request->push_time ? strtotime($request->push_time) : null;
        $massModel->content = $request->content ?? '';
        $massModel->material_id = $request->material['material_id'] ?? 0;
        $massModel->card_id = $request->card_id ?? '';
        return $massModel->save();
    }

    /**
     * 删除群发消息
     * @param $massId
     */
    public function del($massId)
    {
        $findMass = WxMass::where('appid', $this->appid)->findOrFail($massId);
        \DB::beginTransaction();
        try {
            if (!empty($findMass->msg_id)) {
                $app = EasyWechat::officialAccount($this->appid);
                $apiRs = $app->broadcasting->delete($findMass->msg_id);
                WxError::checkApiResponse($apiRs);
            }
            $findMass->delete();
            \DB::commit();
        } catch (\Exception $e) {
            \DB::rollBack();
            throw new \Exception($e->getMessage());
        }
        return true;
    }

    /**
     * 查看群发状态
     * @param $massId
     */
    public function status($massId)
    {
        $findMass = WxMass::where('appid', $this->appid)->findOrFail($massId);
        $msgId = $findMass->msg_id;
        if (empty($msgId)) {
            throw new \Exception('群发还未提交，不能查看');
        }
        $app = EasyWechat::officialAccount($this->appid);
        $apiRs = $app->broadcasting->status($msgId);
        WxError::checkApiResponse($apiRs);
        $findMass->errmsg = $apiRs['msg_status'];
        $findMass->save();
        return $apiRs['msg_status'] ?? '';
    }

    /**
     * 创建群发对象
     * @param $type
     * @return \App\Services\WxMass\Factory\WxMassAbstract
     */
    public function createMassObject($type)
    {
        if (!array_key_exists($type, $this->typeObjectList)) {
            throw new \InvalidArgumentException("$type 无效的消息类型");
        }
        return new $this->typeObjectList[$type];
    }

    /**
     * 定时群发
     * @return bool
     */
    public function massDelayedSend()
    {
        $massList = WxMass::where('appid', $this->appid)->where('is_open', 1)->where('is_send', 0)->where('msg_id', 0)->get();
        if (!empty($massList)) {
            foreach ($massList as $massData) {
                if (empty($massData->push_time) || strtotime($massData->push_time) <= time()) {
                    $this->createMassObject($massData->msg_type)->handleSend($massData->mass_id);
                }
            }
        }
        return true;
    }

    /**
     * 微信群发结果处理
     * @param $eventData
     */
    public function sendResultHandle($eventData)
    {
        $massData = WxMass::where('appid', $this->appid)->where('msg_id', $eventData['MsgID'])->first();
        if (!empty($massData)) {
            $this->createMassObject($massData->msg_type)->handleCallback($eventData);
        }
        return true;
    }

    /**
     * 获取群发配置，key为速度级别，value为群发速度的真实值 单位：万/分钟
     * @return array
     */
    public function getSpeedTypeList()
    {
        return [
            0 => 80,
            1 => 60,
            2 => 45,
            3 => 30,
            4 => 10,
        ];
    }

    /**
     * 获取群发速度
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function getSpeed()
    {
        $sysConfig = new SysConfigService();
        //缓存KEY
        $key = SysConfigService::WX_MASS_SPEED .'_'.$this->appid;
        $speed = $sysConfig->get($key);
        if (empty($speed)) {
            $app = EasyWechat::officialAccount($this->appid);
            $apiRs = $app->base->httpPost('cgi-bin/message/mass/speed/get');
            WxError::checkApiResponse($apiRs);
            $sysConfig->set(SysConfigService::WX_MASS_SPEED, $apiRs);
        }
        return $speed;
    }

    /**
     * 保存群发速度
     * @param $speed
     * @throws \Exception
     */
    public function saveSpeed($speed)
    {
        $speedConfig = $this->getSpeedTypeList();
        if (!isset($speedConfig[$speed])) {
            throw new \Exception('改群发速度无效');
        }
        \DB::beginTransaction();
        try {
            $app = EasyWechat::officialAccount($this->appid);
            $apiRs = $app->base->httpPostJson('cgi-bin/message/mass/speed/set', ['speed'=>$speed]);
            WxError::checkApiResponse($apiRs);
            $configData = ['speed' => $speed, 'realspeed' => $speedConfig[$speed]];
            //缓存KEY
            $key = SysConfigService::WX_MASS_SPEED .'_'.$this->appid;
            (new SysConfigService())->set($key, $configData);
            \DB::commit();
        } catch (\Exception $e) {
            \DB::rollBack();
            throw new \Exception($e->getMessage());
        }
        return true;
    }
}